package com.coocaa.ops.common.tool.reflect;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;

/**
 * @author tangminghong
 * @date 2020-06-10 18:11
 */
@Slf4j
public class ReflectUtil {

    /**
     * 获取类的父类的泛型类型-第一个位置
     *
     * @param clazz
     * @param <T>
     * @return
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static <T> Class<T> getSuperClassGenricType(final Class clazz) {
        return getSuperClassGenricType(clazz, 0);
    }

    /**
     * 获取类的父类的泛型类型-指定位置
     *
     * @param clazz
     * @param index
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Class getSuperClassGenricType(final Class clazz, final int index) {
        //获取类的泛型类型
        Type genType = clazz.getGenericSuperclass();
        //如果不是参数化泛型类型
        if (!(genType instanceof ParameterizedType)) {
            log.warn(clazz.getSimpleName()
                    + "'s superclass not ParameterizedType");
            return Object.class;
        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        //如果位置值 越界
        if (index >= params.length || index < 0) {
            log.warn("Index: " + index + ", Size of "
                    + clazz.getSimpleName() + "'s Parameterized Type: "
                    + params.length);
            return Object.class;
        }
        //如果该泛型类型 不是实体类
        if (!(params[index] instanceof Class)) {
            log.warn(clazz.getSimpleName()
                    + " not set the actual class on superclass generic parameter");
            return Object.class;
        }

        return (Class) params[index];
    }


    public static void invokeBeanMethodRs(Object bean, String method, Object param) throws Exception {
        Class<? extends Object> clazz = bean.getClass();
        Method meth = clazz.getDeclaredMethod(method, Map.class);
        meth.invoke(bean, param);
    }

    public static void invokeBeanMethodRs(Object bean, String method) throws Exception {
        Class<? extends Object> clazz = bean.getClass();
        Method meth = clazz.getDeclaredMethod(method, (Class[]) null);
        meth.invoke(bean);
    }

    public static Object invokeBeanMethod(Object bean, String method, Map<String, Object> param) throws Exception {
        Class<? extends Object> clazz = bean.getClass();
        Method meth = clazz.getDeclaredMethod(method, Map.class);
        return meth.invoke(bean, param);
    }

    public static Object invokeBeanMethod(Object bean, String method, Object param) throws Exception {
        Class<? extends Object> clazz = bean.getClass();
        Method meth = clazz.getDeclaredMethod(method, Object.class);
        return meth.invoke(bean, param);
    }

    public static Object invokeBeanMethod(Object bean, String method) throws Exception {
        Class<? extends Object> clazz = bean.getClass();
        Method meth = clazz.getDeclaredMethod(method, (Class[]) null);
        return meth.invoke(bean);
    }

    public static void setFieldValue(Object target, String fname, Class ftype, Object fvalue) {
        if (target != null && fname != null && !"".equals(fname) && (fvalue == null || ftype.isAssignableFrom(fvalue.getClass()))) {
            Class clazz = target.getClass();

            try {
                String methodname = "set" + Character.toUpperCase(fname.charAt(0)) + fname.substring(1);
                Method method = clazz.getDeclaredMethod(methodname, ftype);
                if (!Modifier.isPublic(method.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        @Override
                        public Object run() {
                            method.setAccessible(true);
                            return null;
                        }
                    });
                }

                method.invoke(target, fvalue);
            } catch (Exception var8) {
                try {
                    Field field = clazz.getDeclaredField(fname);
                    if (!Modifier.isPublic(field.getModifiers())) {
                        AccessController.doPrivileged(new PrivilegedAction<Object>() {
                            @Override
                            public Object run() {
                                field.setAccessible(true);
                                return null;
                            }
                        });
                    }

                    field.set(target, fvalue);
                } catch (Exception var7) {
                    ;
                }
            }

        }
    }

    public static Object getFieldValue(Object target, String fname, Class ftype) {
        if (target != null && fname != null && !"".equals(fname)) {
            Class clazz = target.getClass();
            try {
                String methodname = "get" + Character.toUpperCase(fname.charAt(0)) + fname.substring(1);
                System.out.println(methodname);
                Method method = clazz.getDeclaredMethod(methodname);
                if (!Modifier.isPublic(method.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        @Override
                        public Object run() {
                            method.setAccessible(true);
                            return null;
                        }
                    });
                }

                return method.invoke(target);
            } catch (Exception var7) {
                try {
                    Field field = clazz.getDeclaredField(fname);
                    if (!Modifier.isPublic(field.getModifiers())) {
                        AccessController.doPrivileged(new PrivilegedAction<Object>() {
                            @Override
                            public Object run() {
                                field.setAccessible(true);
                                return null;
                            }
                        });
                    }

                    return field.get(target);
                } catch (Exception var6) {
                    return null;
                }
            }
        } else {
            return null;
        }
    }
}
